# Getting Started Using RMI

This tutorial shows you the steps to follow to create a distributed version of the classic Hello World program using JavaTM Remote Method Invocation (RMI). While you work through this example, you will probably come up with a number of related questions. You may find the answers in the RMI FAQ, or you may wish to look in the email archives of the rmi-users alias. If you'd like to subscribe to the rmi-users email alias, click here.

The distributed Hello World example uses an applet to make a remote method call to an RMI server, running on the host from which the applet was downloaded. When the applet runs, "Hello World!" is displayed on the client browser.

This tutorial is organized as follows:

1. The steps to write the source files and the HTML file
2. The steps to compile and deploy class files and the HTML file
3. The steps to start the RMI registry, server, and applet

The files needed for this tutorial are:

- `Hello.java` - a remote interface
- `HelloImpl.java` - a remote object implementation that implements `examples.hello.Hello`
- `HelloApplet.java` - an applet that invokes the remote method, `sayHello`
- `hello.html` - the HTML page that references the applet

Note: For the remainder of this tutorial, the terms "remote object implementation," "object implementation," and "implementation" may be used interchangeably to refer to the class, `examples.hello.HelloImpl`, which implements a remote interface.

For all of the source code used in this tutorial, you may choose from the following formats:

- getStart.zip
- getStart.tar
- getStart.tar.Z

# Write the Source and HTML files

Because the JavaTM programming language requires a mapping between the fully-qualified package name of a class and the directory path to that class, you should decide on package and directory names before you begin writing any code written in the Java programming language. This mapping allows the compiler for the Java programming language to know the directory in which to find the class files mentioned in a program. For the programs in this tutorial, the package name is `examples.hello` and the source directory is `$HOME/mysrc/examples/hello`.

To create the directory for your source files in the SolarisTM operating environment, execute the command:

        mkdir -p $HOME/mysrc/examples/hello

On Microsoft Windows platforms, you would go to the directory of your choice, and type:

        mkdir mysrc
        mkdir mysrc\examples
        mkdir mysrc\examples\hello

There are three tasks to complete in this section:

1. Define the functions of the remote class as an interface written in the Java programming language
2. Write the implementation and server classes
3. Write a client program that uses the remote service

## Define the functions of the remote class as an interface written in the Java programming language

In the Java programming language, a remote object is an instance of a class that implements a `Remote` interface. Your remote interface will declare each of the methods that you would like to call from other JavaTM virtual machines* (JVMs). Remote interfaces have the following characteristics:

- The remote interface must be declared `public`. Otherwise, a client will get an error when attempting to load a remote object that implements the remote interface, unless that client is in the same package as the remote interface.
- The remote interface extends the `java.rmi.Remote` interface.
- Each method must declare `java.rmi.RemoteException` (or a superclass of `RemoteException`) in its `throws` clause, in addition to any application-specific exceptions.
- The data type of any remote object that is passed as an argument or return value (either directly or embedded within a local object) must be declared as the remote interface type (for example, `Hello`) not the implementation class (`HelloImpl`).

Here is the interface definition for the remote interface, `examples.hello.Hello`. The interface contains just one method, `sayHello`, which returns a string to the caller:

        package examples.hello;

        import java.rmi.Remote;
        import java.rmi.RemoteException;

        public interface Hello extends Remote {
    	String sayHello() throws RemoteException;
        }

Because remote method invocations can fail in very different ways from local method invocations (due to network-related communication problems and server problems), remote methods will report communication failures by throwing a `java.rmi.RemoteException`. If you want more information on failure and recovery in distributed systems, you may wish to read A Note on Distributed Computing.

## Write the implementation and server classes

At a minimum, a remote object implementation class must:

- Declare that it implements at least one remote interface
- Define the constructor for the remote object
- Provide implementations for the methods that can be invoked remotely

A "server" class, in this context, is the class which has a `main` method that creates an instance of the remote object implementation, and binds that instance to a name in the `rmiregistry`. The class that contains this `main` method could be the implementation class itself, or another class entirely.

In this example, the `main` method is part of `examples.hello.HelloImpl`. The server program needs to:

- Create and install a security manager
- Create one or more instances of a remote object
- Register at least one of the remote objects with the RMI remote object registry, for bootstrapping purposes

An explanation of each of the preceding six steps follows the source for `HelloImpl.java:`

    	package examples.hello;

    	import java.rmi.Naming;
    	import java.rmi.RemoteException;
    	import java.rmi.RMISecurityManager;
    	import java.rmi.server.UnicastRemoteObject;

    	public class HelloImpl extends UnicastRemoteObject implements Hello {

    	    public HelloImpl() throws RemoteException {
    		super();
    	    }

    	    public String sayHello() {
    		return "Hello World!";
    	    }

    	    public static void main(String args[]) {

    		// Create and install a security manager
    		if (System.getSecurityManager() == null) {
    		    System.setSecurityManager(new RMISecurityManager());
    		}

    		try {
    		    HelloImpl obj = new HelloImpl();

    		    // Bind this object instance to the name "HelloServer"
    		    Naming.rebind("//myhost/HelloServer", obj);

    		    System.out.println("HelloServer bound in registry");
    		} catch (Exception e) {
    		    System.out.println("HelloImpl err: " + e.getMessage());
    		    e.printStackTrace();
    		}
    	    }
    	}

> ### Implement a remote interface

> In the Java programming language, when a class declares that it implements an interface, a contract is formed between the class and the compiler. By entering into this contract, the class is promising that it will provide method bodies, or definitions, for each of the method signatures declared in that interface. Interface methods are implicitly `public` and `abstract`, so if the implementation class doesn't fulfill its contract, it becomes by definition an `abstract` class, and the compiler will point out this fact if the class was not declared `abstract`.

> The implementation class in this example is `examples.hello.HelloImpl`. The implementation class declares which remote interface(s) it is implementing. Here is the `HelloImpl` class declaration:

>     	public class HelloImpl extends UnicastRemoteObject
>     	    implements Hello {

> As a convenience, the implementation class can extend a remote class, which in this example is `java.rmi.server.UnicastRemoteObject`. By extending `UnicastRemoteObject`, the `HelloImpl` class can be used to create a remote object that:
> - Uses RMI's default sockets-based transport for communication
> - Runs all the time
> If you want a remote object that can be activated (created) when a client requests it, rather than running all the time, after you finish this tutorial, you can take a look at the RMI Activation tutorial. Also, you can learn about how to use your own communication protocol, rather than the TCP sockets that RMI uses by default, in the tutorial on Using a Custom RMI Socket Factory.

> ### Define the constructor for the remote object

> The constructor for a remote class provides the same functionality as the constructor for a non-remote class: it initializes the variables of each newly created instance of the class, and returns an instance of the class to the program which called the constructor.

> In addition, the remote object instance will need to be "exported". Exporting a remote object makes it available to accept incoming remote method requests, by listening for incoming calls to the remote object on an anonymous port. When you extend `java.rmi.server.UnicastRemoteObject` or `java.rmi.activation.Activatable`, your class will be exported automatically upon creation.

> If you choose to extend a remote object from any class other than `UnicastRemoteObject` or `Activatable`, you will need to explicitly export the remote object by calling either the `UnicastRemoteObject.exportObject` method or the `Activatable.exportObject` method from your class's constructor (or another initialization method, as appropriate).

> Because the object export could potentially throw a `java.rmi.RemoteException`, you must define a constructor that throws a `RemoteException`, even if the constructor does nothing else. If you forget the constructor, `javac` will produce the following error message:

>     	HelloImpl.java:13: Exception java.rmi.RemoteException must be caught, or it must be
>             declared in the throws clause of this method.
>                     super();
>                          ^
>             1 error

> To review: The implementation class for a remote object needs to:
> - Implement a remote interface
> - Export the object so that it can accept incoming remote method calls
> - Declare its constructor(s) to throw at least a `java.rmi.RemoteException`
> Here is the constructor for the `examples.hello.HelloImpl` class:

>         public HelloImpl() throws RemoteException {
>     	super();
>         }

> Note the following:
> - The `super` method call invokes the no-argument constructor of `java.rmi.server.UnicastRemoteObject`, which exports the remote object.
> - The constructor must throw `java.rmi.RemoteException`, because RMI's attempt to export a remote object during construction might fail if communication resources are not available.

> If you are interested in why `java.rmi.RemoteException` is a checked exception rather than runtime exception, please refer to the archives of the rmi-users email list:

> `http://java.sun.com/products/jdk/rmi/archives/3490.html`

> Although the call to the superclass's no-argument constructor, `super()`, occurs by default (even if omitted), it is included in this example to make clear the fact that the Java virtual machine (JVM) constructs the superclass before the class.

> ### Provide an implementation for each remote method

> The implementation class for a remote object contains the code that implements each of the remote methods specified in the remote interface. For example, here is the implementation for the `sayHello` method, which returns the string "Hello World!" to the caller:

>         public String sayHello() throws RemoteException {
>     	return "Hello World!";
>         }

> Arguments to, or return values from, remote methods can be any data type for the Java platform, including objects, as long as those objects implement the interface `java.io.Serializable`. Most of the core classes in `java.lang` and `java.util` implement the `Serializable` interface. In RMI:
> - By default, local objects are passed by copy, which means that all data members (or fields) of an object are copied, except those marked as `static` or `transient`. Please refer to the Java Object Serialization Specification for information on how to alter the default serialization behavior.
> - Remote objects are passed by reference. A reference to a remote object is actually a reference to a stub, which is a client-side proxy for the remote object. Stubs are described fully in the Java Remote Method Invocation Specification. We'll create them later in this tutorial in the section: Use `rmic` to generate stubs and skeletons.
> A class can define methods not specified in the remote interface, but those methods can only be invoked within the virtual machine running the service and cannot be invoked remotely.

> ### Create and install a security manager

> The `main` method of the server first needs to create and install a security manager: either the `RMISecurityManager` or one that you have defined yourself. For example:

>     if (System.getSecurityManager() == null) {

>             System.setSecurityManager(new RMISecurityManager());
>     }

> A security manager needs to be running so that it can guarantee that the classes that get loaded do not perform operations that they are not allowed to perform. If no security manager is specified no class loading, by RMI clients or servers, is allowed, aside from what can be found in the local CLASSPATH. In this example, a security manager is not installed in the client code because applets use the security manager already installed in the client browser. If the client were an application rather than an applet, however, you would need to use the same procedure as is used above to install a security manager in the client. A security manager is required in any JVM that needs to download code, and RMI clients need to download RMI stubs (as well as any other custom classes or interfaces needed to communicate with the RMI server).

> ### Create one or more instances of a remote object

> The `main` method of the server needs to create one or more instances of the remote object implementation which provides the service. For example:

>     HelloImpl obj = new HelloImpl();

> The constructor exports the remote object, which means that once created, the remote object is ready to accept incoming calls.

> ### Register the remote object

> For a caller (client, peer, or applet) to be able to invoke a method on a remote object, that caller must first obtain a reference to the remote object.

> For bootstrapping, the RMI system provides a remote object registry that allows you to bind a URL-formatted name of the form "`//host/objectname`" to the remote object, where `objectname` is a simple string name.

> The RMI registry is a simple server-side name service that allows remote clients to get a reference to a remote object. It is typically used only to locate the first remote object an RMI client needs to talk to. Then that first object would in turn provide application-specific support for finding other objects.

> For example, the reference can be obtained as a parameter to, or a return value from, another remote method call. For a discussion on how this works, please take a look at Applying the Factory Pattern to RMI.

> Once a remote object is registered on the server, callers can look up the object by name, obtain a remote object reference, and then remotely invoke methods on the object.

> For example, the following code binds the name "HelloServer" to a reference for the remote object:

> `Naming.rebind("//myhost/HelloServer", obj);`
> Note the following about the arguments to the `rebind` method call:
> - The first parameter is a URL-formatted `java.lang.String`, representing the location and name of the remote object.

>   - No protocol needs to be specified in the URL-formatted string.
>   - You will need to change the value of `myhost` to be the name or IP address of your server machine; otherwise, the remote object host defaults to the current host. For example, "`HelloServer`" is a valid name string that refers to a remote object bound to the name `HelloServer`, running on the local host.
>   - Optionally, a port number can be supplied in the URL-formatted string. Specifying the port number is necessary when the registry that needs to be contacted is running on a port other than the default port, 1099. For example, "`//myhost:1234/HelloServer`" is a valid name string for the `HelloServer` remote object, reachable through an RMI registry that is running on the host `myhost` and is listening for incoming calls on port 1234.

> - The second parameter is a reference to the object implementation, on which remote methods will be invoked.

> - Once an object is exported, the RMI runtime substitutes a reference to the remote object's stub for the actual remote object reference specified by the `obj` argument. When a client performs a lookup in a server's remote object registry, a serialized instance of the stub for the implementation is returned.
> For security reasons, an application can bind or unbind only to a registry running on the same host. This prevents a client from removing or overwriting any of the entries in a server's remote registry. A lookup, however, can be done from any host.

## Write a client program that uses the remote service

The applet in this example remotely invokes the `sayHello` method in order to get the string "Hello World!" to display when the applet runs. Here is the code for the applet:

>     package examples.hello;

>     import java.applet.Applet;
>     import java.awt.Graphics;
>     import java.rmi.Naming;
>     import java.rmi.RemoteException;

>     public class HelloApplet extends Applet {

>         String message = "blank";

>         // "obj" is the identifier that we'll use to refer
>         // to the remote object that implements the "Hello"
>         // interface
>         Hello obj = null;

>         public void init() {
>             try {
>                 obj = (Hello)Naming.lookup("//" +
>                     getCodeBase().getHost() + "/HelloServer");
>                 message = obj.sayHello();
>             } catch (Exception e) {
>                 System.out.println("HelloApplet exception: " + e.getMessage());
>                 e.printStackTrace();
>             }
>         }

>         public void paint(Graphics g) {
>             g.drawString(message, 25, 50);
>         }
>     }

1. First, the applet gets a reference to the remote object implementation (advertised as "HelloServer") from the server host's `rmiregistry`. Like the `Naming.rebind` method, the `Naming.lookup` method takes a URL-formatted `java.lang.String`. In this example, the applet constructs the URL string by using the `getCodeBase` method in conjunction with the `getHost` method. `Naming.lookup` takes care of the following tasks:

   - Constructing a registry stub instance (to contact the server's registry) using the hostname and port number supplied as arguments to `Naming.lookup`
   - Using the registry stub to call the remote `lookup` method on the registry, using the URL's name component ("`HelloServer`")

     - The registry returns the `HelloImpl_Stub` instance bound to that name
     - The `lookup` method receives the remote object's (`HelloImpl`) stub instance and loads the stub class (`examples.hello.HelloImpl_Stub`) from the CLASSPATH or the applet's codebase

   - `Naming.lookup` returns the stub to its caller (`HelloApplet`)

2. The applet invokes the remote `sayHello` method on the server's remote object

   - RMI serializes and returns the reply string "Hello World!"
   - RMI deserializes the string and stores it in a variable named `message`.

3. The applet invokes the `paint` method, causing the string "Hello World!" to be displayed in the drawing area of the applet.

The URL-formatted string that is passed as a parameter to the `Naming.lookup` method must include the server's hostname. Otherwise, the applet's lookup attempt will default to the client, and the `AppletSecurityManager` will throw an exception because the applet cannot access the local system, but is instead limited to only communicating with the applet's host.

Here is the HTML code for the web page that references the Hello World applet:

    	<HTML>
    	<title>Hello World</title>
    	<center> <h1>Hello World</h1> </center>
    	<applet codebase="myclasses/"
    	        code="examples.hello.HelloApplet"
    	        width=500 height=120>
    	</applet>
    	</HTML>

Note the following:

- There needs to be an HTTP server running on the machine from which you want to download classes.
- The `codebase` in the HTML file specifies a directory below the directory from which the web page was itself loaded. Using this kind of relative path is usually a good idea. For example, if the `codebase` directory (where the applet's class files live), referenced by the applet's HTML, was in the directory above the the HTML directory, you would use the relative path, "../".
- The applet's `code` attribute specifies the fully-qualified package name of the applet, in this example `examples.hello.HelloApplet`:

      code="examples.hello.HelloApplet"

# Compile and Deploy Class Files and HTML Files

The source code for this example is now complete and the `$HOME/mysrc/examples/hello` directory has four files:

- `Hello.java` contains the source code for the `Hello` remote interface
- `HelloImpl.java` contains the source code for the `HelloImpl` remote object implementation and the RMI server for the applet
- `HelloApplet.java` contains the source code for the applet
- `hello.html` is the web page that references the Hello World applet.

In this section, you compile the `.java` source files to create `.class` files. You then run the `rmic` compiler to create stubs and skeletons. A stub is a client-side proxy for a remote object which forwards RMI calls to the server-side dispatcher, which in turn forwards the call to the actual remote object implementation.

When you use the `javac` and `rmic` compilers, you must specify where the resulting class files should reside. For applets, all files should be in the applet's codebase directory. For our example, this directory is `$HOME/public_html/myclasses`.

Some web servers allow accessing a user's public_html directory via an HTTP URL constructed as `"http://host/~username/"`. If your web server does not support this convention, you could use a file URL of the form `"file:/home/username/public_html"` for testing, but this approach will limit you to communicating between a client and server that have access to the same physical file system. As an alternative, you can use an HTTP URL by setting up a minimal web server on your system; we have one available for download here.

There are four tasks to complete in this section:

1. Compile the source files
2. Use `rmic` to generate stubs and skeletons
3. Move the HTML file to the deployment directory
4. Set paths for runtime

> ## Compile the source files

> Make sure that the deployment directory `$HOME/public_html/myclasses` and the development directory `$HOME/mysrc/examples/hello` are each accessible through the local `CLASSPATH` on the development machine before attempting to compile.

> To compile the source files, run the `javac` command as follows:

> `javac -d $HOME/public_html/myclasses Hello.java HelloImpl.java HelloApplet.java`

> This command creates the directory `examples/hello` (if it does not already exist) in the directory `$HOME/public_html/myclasses`. The command then writes to that directory the files `Hello.class`, `HelloImpl.class`, and `HelloApplet.class`. These are the remote interface, the implementation, and the applet respectively. For an explanation of `javac` options, you can refer to the Solaris `javac` manual page or the Win32 `javac` manual page.

> ## Use `rmic` to generate skeletons and/or stubs

> To create stub and skeleton files, run the `rmic` compiler on the fully-qualified package names of compiled class files that contain remote object implementations, like `my.package.MyImpl`. The `rmic` command takes one or more class names as an argument and produces class files of the form `MyImpl_Skel.class` and `MyImpl_Stub.class`.

> By default, in the Java 2 SDK, v1.2 and later, `rmic` runs with the `-vcompat` flag on, which produces stubs and skeletons that support access to:

> 1. Unicast (not `Activatable`) remote objects from 1.1 clients and
> 2. All types of remote objects from 1.2 (and later) clients
> If you will never need support for 1.1 clients, `rmic` can be run with the `-v1.2` option. For an explanation of `rmic` options, you can refer to the Solaris `rmic` manual page or the Win32 `rmic` manual page.

> For example, to create the stub and skeleton for the `HelloImpl` remote object implementation, run `rmic` like this:

> `rmic -d $HOME/public_html/`myclasses` examples.hello.HelloImpl`

> The "`-d`" option indicates the root directory in which to place the compiled stub and skeleton class files. So the preceding command creates the following files in the directory `$HOME/public_html/myclasses/examples/hello`:

> - `HelloImpl_Stub.class`
> - `HelloImpl_Skel.class`
> The generated stub class implements exactly the same set of remote interfaces as the remote object itself. This means that a client can use the Java programming language's built-in operators for casting and type checking. It also means that remote objects written for the Java platform support true object-oriented polymorphism.

> ## Move the HTML file to the deployment directory

> To make the web page that references the applet visible to clients, the `hello.html` file must be moved from the development directory to the applet's `codebase` directory. For example:

> `mv $HOME/mysrc/examples/hello/hello.html $HOME/public_html/`

> ## Set paths for runtime

> Make sure that the $`HOME/public_html/myclasses` directory is available through the server's local `CLASSPATH` when you run the `HelloImpl` server.

# Start the RMI registry, server, and applet

There are three tasks to complete in this section:

1. Start the RMI registry
2. Start the server
3. Run the applet

> ## Start the RMI registry

> The RMI registry is a simple server-side name server that allows remote clients to get a reference to a remote object. Typically, it is used only to locate the first remote object an application needs to talk to. Then that object in turn would provide application-specific support for finding other objects.

> Note: Before you start the `rmiregistry`, you must make sure that the shell or window in which you will run the registry either has no CLASSPATH set or has a CLASSPATH that does not include the path to any classes that you want downloaded to your client, including the stubs for your remote object implementation classes.

> If you start the `rmiregistry`, and it can find your stub classes in its CLASSPATH, it will ignore the server's `java.rmi.server.codebase` property, and as a result, your client(s) will not be able to download the stub code for your remote object. For an explanation of how code downloading works in RMI, please take a look at the tutorial on Dynamic code downloading using RMI.

> To start the registry on the server, execute the `rmiregistry` command. This command produces no output and is typically run in the background. For more on the `rmiregistry`, you can refer to the Solaris `rmiregistry` manual page or the Win32 `rmiregistry` manual page.

> For example, in the Solaris operating environment:

>     rmiregistry &

> For example, on Microsoft Windows 95 systems:

>     start rmiregistry

> (Use `javaw` if start is not available.)

> By default, the registry runs on port 1099. To start the registry on a different port, specify the port number from the command line. For example, to start the registry on port 2001 on a Microsoft Windows NT system:

>     start rmiregistry 2001

> If the registry is running on a port other than 1099, you'll need to specify the port number in the name handed to the URL-based methods of the `java.rmi.Naming` class when making calls to the registry. For example, if the registry is running on port 2001 in this example, the call required to bind the name "`HelloServer`" to the remote object reference would be:

>     Naming.rebind("//myhost:2001/HelloServer", obj);

> You must stop and restart the registry any time you modify a remote interface or use modified/additional remote interfaces in a remote object implementation. Otherwise, the type of the object reference bound in the registry will not match the modified class.

> ## Start the server

> When starting the server, the `java.rmi.server.codebase` property must be specified, so that the stub class can be dynamically downloaded to the registry and then to the client. Run the server, setting the codebase property to be the location of the implementation stubs. Because the codebase property in this example references a directory, make sure that any other classes that may need to be downloaded have also been installed in the directory referenced by `java.rmi.server.codebase`. For other command-line examples of codebase settings, please take a look at the tutorial on Dynamic code downloading using RMI.

> For explanations of each of the `java.rmi.server` properties, click here. To see all the available `java.rmi.activation` properties, click here. For an explanation of `java` options, you can refer to the Solaris `java` manual page

or the Win32 `java` manual page. If you have problems running the example code, please take a look at the RMI and Serialization FAQ.

Note: A stub class is dynamically downloaded to a client's virtual machine only when the class is not already available locally and the `java.rmi.server.codebase` property has been set properly to specify where the class files are located on the server.

There are four things that need to go on the same command line: the "`java`" command, followed by two property name=value pairs (for the `codebase` property, note that there are no spaces from the "-D" all the way though the last "/") and then the fully-qualified package name of the server program. There should be a space just after the word "`java`", between the two properties, and just before the word "`examples`" (which is very hard to see when you view this as text, in a browser, or on paper). The following command shows how to start the `HelloImpl` server, specifying the `java.rmi.server.codebase` and `java.security.policy` properties:

`java -Djava.rmi.server.codebase=http://myhost/~myusrname/myclasses/ -Djava.security.policy=$HOME/mysrc/policy examples.hello.HelloImpl`

In order to run this code on your system, you'll need to change the location of the `policy` file to be the location of the directory on your system, where you've installed the example source code.

Note: In this example, for simplicity, we will use a policy file that gives global permission to anyone from anywhere. Do not use this policy file in a production environment. For more information on how to properly open up permissions using a `java.security.policy` file, please refer to to the following documents:

`Default Policy Implementation and Policy File Syntax`

`Permissions in the Java 2 SDK`

The codebase property will be resolved to a URL, so it must have the form of "`http://aHost/somesource/`" or "`file:/myDirectory/location`/" or, due to the requirements of some operating systems, "`file:///myDirectory/location/`" (three slashes after the "file:").

Please note that each of the URL strings above has a trailing "/". The trailing slash is a requirement for the URL set by `the java.rmi.server.codebase` property, so the implementation can resolve (find) your class definition(s) properly.

If you forget the trailing slash on the `codebase` property, or if the class files can't be located at the source (they aren't really being made available for download) or if you misspell the property name, you'll get thrown a java.lang.ClassNotFoundException. This exception will be thrown when you try to bind your remote object to the `rmiregistry`, or when the first client attempts to access that object's stub. If the latter case occurs, you have another problem as well because the `rmiregistry` was finding the stubs in its CLASSPATH.

The output should look like this:

`HelloServer bound in registry`

## Run the applet

Once the registry and server are running, the applet can be run. An applet is run by loading its web page into a browser or `appletviewer`, as shown here:

    appletviewer http://myhost/~myusrname/hello.html &

After running the appletviewer, you will see output similar to the following on your display:

*As used on this web site, the terms "Java virtual machine" or "JVM" mean a virtual machine for the Java platform.

Copyright © 2001 Sun Microsystems, Inc. All Rights Reserved. Please send comments to: rmi-comments@java.sun.com |